package cn.xinfei.xdecision.engine.runner.context;

import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.datax.datainterface.v2.VariableVO;
import cn.xinfei.xdecision.common.model.enginex.model.RuleHitModel;
import cn.xinfei.xdecision.common.model.enginex.model.RuleSetDecisionResultData;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.model.enginex.vo.EngineVersionInOutVarsRespVo;
import cn.xinfei.xdecision.util.DataValueCastUtils;
import cn.xinfei.xdecision.common.utils.util.JsonUtil;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.constant.GlobalConstant;
import cn.xinfei.xdecision.nacos.NacosSwitchProperties;
import cn.xinfei.xdecision.engine.runner.context.model.ChildNodeContextModel;
import cn.xinfei.xdecision.engine.runner.context.model.CreditNodeContextModel;
import cn.xinfei.xdecision.engine.runner.context.model.NodeContextModel;
import cn.xinfei.xdecision.engine.runner.context.model.TrackModel;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.metadata.MetadataProvider;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.slf4j.MDC;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

@Data
@Slf4j
public class PipelineContextHolder {


    public static PipelineContext getPipelineContext() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext;
    }



    public static void clear() {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        ConcurrentHashMap<String, Object> context = pipelineContext.getContext();
        ConcurrentHashMap<String, List<TrackModel>> track = pipelineContext.getTrack();
        track.clear();
        context.clear();
    }

    public static void putInTrace(NodeHandler nodeHandler) {

        EngineNode engineNode = nodeHandler.getEngineNode();
        String engineCode = engineNode.getEngineCode();
        String nodeCode = engineNode.getNodeCode();
        XDecisionContext context = XDecisionContext.getContext();
        if (StringUtils.isNotEmpty(nodeCode) && StringUtils.isNotEmpty(engineCode)) {
            ConcurrentHashMap<String, List<TrackModel>> track = context.getPipelineContext().getTrack();
            long start = System.currentTimeMillis();
//            if (!track.containsKey(engineCode)) {
//                track.computeIfAbsent(engineCode, key -> track.put(engineCode, new ArrayList<TrackModel>()));
////                synchronized (engineCode.intern()) {
////                    if (!track.containsKey(engineCode)) {
////                        track.put(engineCode, new ArrayList<TrackModel>());
////                    }
////                }
//            }
            List<TrackModel> trackModels = track.get(engineCode);
            TrackModel trackModel = new TrackModel();
//            trackModel.setEngineCode(engineCode);
//            trackModel.setVersionNo(engineNode.getEngineVersion());
            trackModel.setNodeName(engineNode.getNodeName());
            trackModel.setNodeCode(nodeCode);
            trackModel.setNodeType(engineNode.getNodeType());
            trackModels.add(trackModel);
            long end = System.currentTimeMillis();
            log.info("trackModel={},trackDuration={}", JsonUtil.toJson(trackModel), end - start);
        } else {
            log.error("追踪的engineCode为null");
        }
    }

    public static Object putInContext(String key, Object currValue) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        ConcurrentHashMap<String, Object> contextContext = pipelineContext.getContext();
        if (null != currValue) {
            return contextContext.put(key, currValue);
        }
        log.warn("变量value值为空，{}={}", key, currValue);
        return currValue;
    }

    public static Object putInContext(String nodeCode, String fieldCode, Object currValue) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        ConcurrentHashMap<String, Object> contextContext = pipelineContext.getContext();
        if (null != currValue) {
            FieldInfoVo fieldInfoVo = MetadataProvider.fieldMapCache.get(fieldCode);
            if (Objects.nonNull(fieldInfoVo)) {
                Object cast = DataValueCastUtils.cast(fieldCode, currValue, fieldInfoVo.getValueType());
                if (Objects.nonNull(cast)) {
                    currValue = cast;
                }
            }
            return contextContext.put(fieldCode, currValue);
        }
        log.warn("变量value值为空，nodeCode={},{}}={}", nodeCode, fieldCode, currValue);
        return currValue;
    }


    /**
     * 存储入参
     *
     * @param m
     */
    public static void putInput(Map<? extends String, ?> m) {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        pipelineContext.getInput().putAll(m);
        PipelineContextHolder.putInContext("input", m);
    }

    public static void putInContext(String nodeCode, Map<? extends String, ?> m) {
        log.info("putAll to context ,value={}", JsonUtil.toJson(m));
        m.entrySet().stream().forEach(entry -> {
            try {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value != null) {
                    putInContext(nodeCode, key, value);
                } else {
                    putInContext(nodeCode, key, "null");
                    log.warn("变量value值为空,转成'null'，nodeCode={},key={}", nodeCode, key);
                }
            } catch (Exception e) {
                log.error("putInContext fail.msg={},nodeCode={}", e.getMessage(), nodeCode, e);
            }
        });
    }


    public static String getResult(EngineResultEnum engineResultEnum) {
        String finallyResult = null;
        Map<String, Object> out = getOut();
        if (null != out) {
            Object result = out.get("result");
            if (result != null) {
                finallyResult = result.toString();
            }
        }
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(finallyResult)) {
            if (EngineResultEnum.SUCCESS_HIT_END == engineResultEnum) {
                //有决策结果，命中终止条件
                return finallyResult;
            }
            if (EngineResultEnum.SUCCESS_END == engineResultEnum) {
                //有决策结果，执行到end节点
                return finallyResult;
            }
        }
        return engineResultEnum.getResult();
    }

//    public static Map<String, Object> getIn() {
//        XDecisionContext xDecisionContext = XDecisionContext.getContext();
//        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
//        PipelineMetaInfoContext pipelineMetaInfoContext = xDecisionContext.getPipelineMetaInfoContext();
//        Set<String> inputField = pipelineMetaInfoContext.getField(p -> null!=p.getValue().getIsOutput()&&1 == p.getValue().getIsInput());
//        ConcurrentHashMap<String, ContextModel> context = pipelineContext.getContext();
//        Map<String, Object> valueContext = context.entrySet().stream()
//                .filter(x -> x.getValue().getValue() != null && inputField.contains(x.getValue().getKey()))
//                .collect(Collectors.toMap(
//                        e -> e.getKey(),
//                        e -> e.getValue().getValue(),
//                        (a, b) -> Objects.isNull(a) ? b : a));
//
//        return valueContext;
//
//    }

    public static Map<String, Object> getIn() {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        ConcurrentHashMap<String, Object> input = pipelineContext.getInput();
        return input;
    }

    public static Map<String, Object> getOut() {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        ConcurrentHashMap<String, Object> context = pipelineContext.getContext();
        Map<String, FieldInfoVo> fieldMapCache = MetadataProvider.fieldMapCache;
        ConcurrentMap<String, Object> valueContext = context.entrySet().stream().filter(entry -> {
            String key = entry.getKey();
            if (fieldMapCache.containsKey(key)) {
                FieldInfoVo fieldInfoVo = fieldMapCache.get(key);
                int isOutput = fieldInfoVo.getIsOutput();
                if (isOutput == 1) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toConcurrentMap(
                e -> e.getKey(),
                e -> e.getValue(),
                (a, b) -> Objects.isNull(a) ? b : a));
        return valueContext;

    }

    //废弃
    public static Map<String, Object> getOut2() {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        PipelineMetaInfoContext pipelineMetaInfoContext = xDecisionContext.getPipelineMetaInfoContext();
        ConcurrentHashMap<String, Object> context = pipelineContext.getContext();

        Set<StrategyOutput> outputField = pipelineMetaInfoContext.getOutputField();
        Map<String, Object> valueContext = new HashMap<>();
        outputField.forEach(strategyOutput -> {
            String fieldCode = strategyOutput.getFieldCode();
            Object val = null;
            if (context.containsKey(fieldCode) && (val = context.get(fieldCode)) != null) {
                valueContext.put(fieldCode, val);
            }
        });


        Set<StrategyOutput> terminalOutputFields = pipelineMetaInfoContext.getTerminalOutputFields();
        terminalOutputFields.forEach(strategyOutput -> {
            String fieldCode = strategyOutput.getFieldCode();
            Object val = null;
            if (context.containsKey(fieldCode) && (val = context.get(fieldCode)) != null) {
                valueContext.put(fieldCode, val);
            }
        });

        //补充state里的输出，规则集的输出，会存在这里，无法重
//        StateTransmitModel stateContext = xDecisionContext.getStateContext();
//        Map<String, Object> nodeOutput = stateContext.getNodeOutput();
//        if(null!=nodeOutput&&nodeOutput.size()>0){
//            valueContext.putAll(nodeOutput);
//        }
        //补充
        String engineCode = pipelineContext.getEngineCode();
        String engineVersion = pipelineContext.getEngineVersion();
        EngineVersionInOutVarsRespVo inOutVarsCache = MetadataProvider.getInOutVarsCache(engineCode, Long.parseLong(engineVersion));
        if (inOutVarsCache != null) {
            List<VariableVO> outVars = inOutVarsCache.getOutVars();
            if (CollectionUtils.isEmpty(outVars) == false) {
                for (int i = 0; i < outVars.size(); i++) {
                    VariableVO variableVO = outVars.get(i);
                    String fieldCode = variableVO.getVarCode();
                    Object val = null;
                    if (context.containsKey(fieldCode) && (val = context.get(fieldCode)) != null) {
                        valueContext.put(fieldCode, val);
                    }
                }
            }
        }

        return valueContext;
    }

    public static ConcurrentMap<String, Object> getContextValue() {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        ConcurrentHashMap<String, Object> context = pipelineContext.getContext();
        return context.entrySet().stream()
                .filter(x -> Objects.nonNull(x.getValue()))
                .collect(Collectors.toConcurrentMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (a, b) -> a));
    }


    public static boolean containsKey(String key) {
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        ConcurrentHashMap<String, Object> context = pipelineContext.getContext();
        return context.containsKey(key);
    }

    /**
     * 不要调用此方法
     * 不要调用此方法
     * 不要调用此方法
     * 统一由方法收口AmmunitionDepot.getValueByKey(varCode)
     * 或者继续重载AmmunitionDepot.getValueByKey(varCode)
     * @param key
     * @return
     */
    public static Object getValueByKey(String key) {
        if (StringUtils.isBlank(key)) {
            return "";
        }
        XDecisionContext xDecisionContext = XDecisionContext.getContext();
        PipelineContext pipelineContext = xDecisionContext.getPipelineContext();
        ConcurrentHashMap<String, Object> context = pipelineContext.getContext();
        String[] array = key.split("\\.");
        if (array.length == 1) {
            FieldInfoVo fieldInfoVo = MetadataProvider.fieldMapCache.get(array[0]);
            if (fieldInfoVo == null) {
                return context.get(array[0]);
            }
            return DataValueCastUtils.cast(key, context.get(array[0]), fieldInfoVo.getValueType());
        }

        ConcurrentHashMap<String, Object> contextTemp = context;
        for (int i = 0; i < array.length; i++) {
            String childKey = array[i];
            //判断是否能找到key
            if (contextTemp.containsKey(childKey)) {
                Object model = contextTemp.get(childKey);
                if (i == array.length - 1) {
                    //todo shiyusen 为什么要返回最后一个?
                    FieldInfoVo fieldInfoVo = MetadataProvider.fieldMapCache.get(childKey);
                    if (fieldInfoVo == null) {
                        return context.get(array[0]);
                    }
                    return DataValueCastUtils.cast(childKey, model, fieldInfoVo.getValueType());
                }
                //如果是数组取length.
                // key=name.length()
                // key=name.array()
                if (i == array.length - 2) {
                    if ("length()".equals(array[array.length - 1])) {
                        return JSON.toJavaObject(JSON.parseArray(JSON.toJSONString(model)), ArrayList.class).size();
                    } else if ("array()".equals(array[array.length - 1])) {
                        return JSON.parseArray(JSON.toJSONString(model));
                    }
                }
                //未找到最后一个数组元素则将其识别为map
                contextTemp = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(model)), ConcurrentHashMap.class);
            }
        }
        return "";
    }

    public static String getDecisionId() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getDecisionId();
    }
    public static String getMainDecisionId() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getMainDecisionId();
    }

    public static void setDecisionId(String decisionId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setDecisionId(decisionId);

    }

    public static void setMainDecisionId(String decisionId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setMainDecisionId(decisionId);

    }
    public static int getOrganId() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getOrganId();
    }

    public static void setOrganId(int organId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setOrganId(organId);
    }

    public static String getSync() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getSync();
    }

    public static void setSync(String sync) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setSync(sync);

    }

    public static Map<String, Object> getOutput() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getOutput();
    }

    public static void updateOutput(Map<String, Object> output) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.getOutput().putAll(output);
    }

    public static void setOutput(Map<String, Object> output) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setOutput(output);
    }

    public static StateTransmitModel getStateTransmitModel() {
        XDecisionContext context = XDecisionContext.getContext();
        return context.getStateContext();
    }

    public static void setStateTransmitModel(StateTransmitModel stateTransmitModel) {
        XDecisionContext context = XDecisionContext.getContext();
        context.setStateContext(stateTransmitModel);
    }

    public static String getRequestId() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getRequestId();
    }

    public static void setRequestId(String requestId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setRequestId(requestId);
    }

    public static void setRespond(long respond) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setRespond(respond);
    }

    public static EngineResultEnum getEngineResult() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        String code = pipelineContext.getCode();
        return EngineResultEnum.getByCode(code);
    }

    public static void setEngineResult(EngineResultEnum engineResultEnum) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setCode(engineResultEnum.getCode());
        pipelineContext.setResult(engineResultEnum.getResult());
        pipelineContext.setState(engineResultEnum.getState());
    }

    public static String getEngineCode() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getEngineCode();
    }

    public static void setEngineCode(String engineCode) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setEngineCode(engineCode);
    }

    public static String getEngineName() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getEngineName();
    }

    public static void setEngineName(String engineName) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setEngineName(engineName);
    }

    public static String getEngineVersion() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getEngineVersion();
    }

    public static void setEngineVersion(String engineVersion) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setEngineVersion(engineVersion);
    }

    public static String getScene() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getScene();
    }

    public static void setScene(String scene) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setScene(scene);
    }

    public static String getTpCode() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getTpCode();
    }

    public static void setTpCode(String tpCode) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setTpCode(tpCode);
    }

    public static String getBranch() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getBranch();
    }

    public static void setBranch(String branch) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        MDC.put(GlobalConstant.BRANCH, branch);
        pipelineContext.setBranch(branch);
    }

    public static void setNodeCodeStack(Stack<NodeContextModel> nodeCodeStack) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setNodeCodeStack(nodeCodeStack);
    }

    public static String getChampionDecisionId() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getChampionDecisionId();
    }

    public static String getParentDecisionId() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getParentDecisionId();
    }

    public static void setParentDecisionId(String parentDecisionId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setParentDecisionId(parentDecisionId);
    }

    public static void setChampionDecisionId(String championDecisionId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setChampionDecisionId(championDecisionId);
    }

    public static void pushCreditNode(String engineCode, String creditState, String creditNodeCode, String decisionId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.getCreditNodeStack().push(new CreditNodeContextModel(engineCode, creditState, creditNodeCode, decisionId));
    }

    public static void pushChildNodeNextNodeCode(String engineCode, String childNodeNextNodeCode, String decisionId, String branch) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<ChildNodeContextModel> childNodeNextNodeCodeStack = pipelineContext.getChildNodeNextNodeCodeStack();
        childNodeNextNodeCodeStack.push(new ChildNodeContextModel(engineCode, childNodeNextNodeCode, decisionId, branch));
    }

    public static int childNodeNextNodeCodeSize() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<ChildNodeContextModel> childNodeNextNodeCodeStack = pipelineContext.getChildNodeNextNodeCodeStack();
        if (null != childNodeNextNodeCodeStack && !childNodeNextNodeCodeStack.empty()) {
            return childNodeNextNodeCodeStack.size();
        }
        return 0;
    }

    public static void pushNodeCode(String engineCode, String nodeCode, String decisionId) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<NodeContextModel> nodeCodeStack = pipelineContext.getNodeCodeStack();
        int size = nodeCodeStack.size();
        NodeContextModel contextModel = new NodeContextModel(engineCode, nodeCode, decisionId);
        nodeCodeStack.push(contextModel);

        if (NacosSwitchProperties.getNacosSwitchProperties().isDebugLog()) {
            log.info("stack push engineCode={}, nodeCode={},before={},after={}", contextModel.getEngineCode(), contextModel.getNodeCode(), size, nodeCodeStack.size());
        }
    }

    public static NodeContextModel peekNodeContextModel() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<NodeContextModel> nodeCodeStack = pipelineContext.getNodeCodeStack();
        if (null != nodeCodeStack && !nodeCodeStack.empty()) {
            return nodeCodeStack.peek();
        }
        return null;
    }

    public static Stack<NodeContextModel> getNodeContextModel() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<NodeContextModel> nodeCodeStack = pipelineContext.getNodeCodeStack();
        return nodeCodeStack;
    }

    public static NodeContextModel popNodeContextModel() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<NodeContextModel> nodeCodeStack = pipelineContext.getNodeCodeStack();
        if (null != nodeCodeStack && !nodeCodeStack.empty()) {
            NodeContextModel nodeContextModel = nodeCodeStack.peek();
            if (nodeContextModel != null) {
                int size = nodeCodeStack.size();
                NodeContextModel pop = nodeCodeStack.pop();
                log.info("stack pop engineCode={}, nodeCode={},before={},after={}", pop.getEngineCode(), pop.getNodeCode(), size, nodeCodeStack.size());
                return pop;
            }
        }
        return null;
    }

    public static void popNodeContextModel(String nodeCode) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<NodeContextModel> nodeCodeStack = pipelineContext.getNodeCodeStack();
        if (null != nodeCodeStack && !nodeCodeStack.empty()) {
            NodeContextModel nodeContextModel = nodeCodeStack.peek();
            if (nodeContextModel != null && nodeContextModel.getNodeCode().equals(nodeCode)) {
                NodeContextModel pop = nodeCodeStack.pop();
                log.info("stack pop engineCode={}, nodeCode={}", pop.getEngineCode(), pop.getNodeCode());
            }
        }
    }

    public static ChildNodeContextModel popChildNodeNextNodeCode() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<ChildNodeContextModel> childNodeNextNodeCodeStack = pipelineContext.getChildNodeNextNodeCodeStack();
        if (null != childNodeNextNodeCodeStack && !childNodeNextNodeCodeStack.empty()) {
            ChildNodeContextModel childNodeContextModel = childNodeNextNodeCodeStack.peek();
            if (childNodeContextModel != null) {
                return childNodeNextNodeCodeStack.pop();
            }
        }
        return null;
    }

    public static ChildNodeContextModel peekChildNodeNextNodeCode() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<ChildNodeContextModel> childNodeNextNodeCodeStack = pipelineContext.getChildNodeNextNodeCodeStack();
        if (null != childNodeNextNodeCodeStack && !childNodeNextNodeCodeStack.empty()) {
            return childNodeNextNodeCodeStack.peek();
        }
        return null;
    }


    public static void popChildNodeNextNodeCode(String childNodeNextNodeCode) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<ChildNodeContextModel> childNodeNextNodeCodeStack = pipelineContext.getChildNodeNextNodeCodeStack();
        if (null != childNodeNextNodeCodeStack && !childNodeNextNodeCodeStack.empty()) {
            ChildNodeContextModel childNodeContextModel = childNodeNextNodeCodeStack.peek();
            if (childNodeContextModel != null && childNodeContextModel.getChildNodeNextNodeCode().equals(childNodeNextNodeCode)) {
                childNodeNextNodeCodeStack.pop();
            }
        }
    }

    public static CreditNodeContextModel peekCreditNode() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<CreditNodeContextModel> creditNodeStack = pipelineContext.getCreditNodeStack();
        if (null != creditNodeStack && !creditNodeStack.empty()) {
            return creditNodeStack.peek();
        }
        return null;
    }

    public static CreditNodeContextModel popCreditNode() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<CreditNodeContextModel> creditNodeStack = pipelineContext.getCreditNodeStack();
        if (null != creditNodeStack && !creditNodeStack.empty()) {
            CreditNodeContextModel creditNodeContextModel = creditNodeStack.peek();
            if (creditNodeContextModel != null) {
                return creditNodeStack.pop();
            }
        }
        return null;
    }

    public static CreditNodeContextModel popCreditNode(String creditNodeCode) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        Stack<CreditNodeContextModel> creditNodeStack = pipelineContext.getCreditNodeStack();
        if (null != creditNodeStack && !creditNodeStack.empty()) {
            CreditNodeContextModel creditNodeContextModel = creditNodeStack.peek();
            if (creditNodeContextModel != null && creditNodeContextModel.getCreditNodeCode().equals(creditNodeCode)) {
                return creditNodeStack.pop();
            }
        }
        return null;
    }

    public static boolean isInvokeRemote() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.isInvokeRemote();
    }

    public static void setInvokeRemote(boolean exam) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setInvokeRemote(exam);
    }

    public static boolean isPersistence() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.isPersistence();
    }


    public static void setPersistence(boolean exam) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.setPersistence(exam);
    }

    public static PipelineContext deepCopy() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        // 使用Gson序列化进行深拷贝
        Gson gson = new Gson();
        PipelineContext copy = gson.fromJson(gson.toJson(pipelineContext), PipelineContext.class);
        return copy;
    }

    public static String toJson() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return JsonUtil.toJson(pipelineContext);
    }


    public static List<RuleHitModel> getHitResultList() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getHitResultList();
    }

    public static void setHitResultList(List<RuleHitModel> hitResultList) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.getHitResultList().addAll(hitResultList);
    }

    public static List<RuleSetDecisionResultData> getBranchRejectInfo() {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        return pipelineContext.getBranchRejectInfo();
    }


    public static void setBranchRejectInfo(List<RuleSetDecisionResultData> branchRejectInfo) {
        XDecisionContext context = XDecisionContext.getContext();
        PipelineContext pipelineContext = context.getPipelineContext();
        pipelineContext.getBranchRejectInfo().addAll(branchRejectInfo);
    }

}
